/**********
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)

This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
more details.

You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
**********/
// "liveMedia"
// Copyright (c) 1996-2018 Live Networks, Inc.  All rights reserved.
// An abstract parser for MPEG video streams
// C++ header

#ifndef _MPEG_VIDEO_STREAM_PARSER_HH
#define _MPEG_VIDEO_STREAM_PARSER_HH

#ifndef _STREAM_PARSER_HH

#include "StreamParser.hh"

#endif
#ifndef _MPEG_VIDEO_STREAM_FRAMER_HH

#include "include/MPEGVideoStreamFramer.hh"

#endif

////////// MPEGVideoStreamParser definition //////////

class MPEGVideoStreamParser : public StreamParser {
public:
    MPEGVideoStreamParser(MPEGVideoStreamFramer *usingSource,
                          FramedSource *inputSource);

    virtual ~MPEGVideoStreamParser();

public:
    void registerReadInterest(unsigned char *to, unsigned maxSize);

    virtual unsigned parse() = 0;

    // returns the size of the frame that was acquired, or 0 if none was
    // The number of truncated bytes (if any) is given by:
    unsigned numTruncatedBytes() const { return fNumTruncatedBytes; }

protected:
    void setParseState() {
        fSavedTo = fTo;
        fSavedNumTruncatedBytes = fNumTruncatedBytes;
        saveParserState();
    }

    // Record "byte" in the current output frame:
    void saveByte(u_int8_t byte) {
        if (fTo >= fLimit) { // there's no space left
            ++fNumTruncatedBytes;
            return;
        }

        *fTo++ = byte;
    }

    void save4Bytes(u_int32_t word) {
        if (fTo + 4 > fLimit) { // there's no space left
            fNumTruncatedBytes += 4;
            return;
        }

        *fTo++ = word >> 24;
        *fTo++ = word >> 16;
        *fTo++ = word >> 8;
        *fTo++ = word;
    }

    // Save data until we see a sync word (0x000001xx):
    void saveToNextCode(u_int32_t &curWord) {
        saveByte(curWord >> 24);
        curWord = (curWord << 8) | get1Byte();
        while ((curWord & 0xFFFFFF00) != 0x00000100) {
            if ((unsigned) (curWord & 0xFF) > 1) {
                // a sync word definitely doesn't begin anywhere in "curWord"
                save4Bytes(curWord);
                curWord = get4Bytes();
            } else {
                // a sync word might begin in "curWord", although not at its start
                saveByte(curWord >> 24);
                unsigned char newByte = get1Byte();
                curWord = (curWord << 8) | newByte;
            }
        }
    }

    // Skip data until we see a sync word (0x000001xx):
    void skipToNextCode(u_int32_t &curWord) {
        curWord = (curWord << 8) | get1Byte();
        while ((curWord & 0xFFFFFF00) != 0x00000100) {
            if ((unsigned) (curWord & 0xFF) > 1) {
                // a sync word definitely doesn't begin anywhere in "curWord"
                curWord = get4Bytes();
            } else {
                // a sync word might begin in "curWord", although not at its start
                unsigned char newByte = get1Byte();
                curWord = (curWord << 8) | newByte;
            }
        }
    }

protected:
    MPEGVideoStreamFramer *fUsingSource;

    // state of the frame that's currently being read:
    unsigned char *fStartOfFrame;
    unsigned char *fTo;
    unsigned char *fLimit;
    unsigned fNumTruncatedBytes;

    unsigned curFrameSize() { return fTo - fStartOfFrame; }

    unsigned char *fSavedTo;
    unsigned fSavedNumTruncatedBytes;

private: // redefined virtual functions
    virtual void restoreSavedParserState();
};

#endif
